package wzh000;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.google.gson.Gson;

public class Player {

	private TableClient tableClient;

	private String nickName;
	private String localIP;
	private int localPort;
	private List<Client> players;
	private Client leftPlayer;
	private Client rightPlayer;
	private List<Card> cards;
	private Socket leftPlayerSocket;
	private Socket rightPlayerSocket;
	private ServerSocket serverSocket;
	private boolean rightPlayerOut;

	public void setRightPlayerOut() {
		this.rightPlayerOut = true;
	}

	public boolean getRightPlayerOut() {
		return this.rightPlayerOut;
	}

	Player(int port, String nickName) throws Exception {
		tableClient = new TableClient("njaal.net", 9898);
		this.localIP = tableClient.getLocalIP();
		this.nickName = nickName;
		this.localPort = port;
		this.players = new ArrayList<Client>();
		this.cards = new ArrayList<Card>();

		this.serverSocket = new ServerSocket(this.localPort);

	}

	private void response(Client client, String msg) {
		String inMsg = null;
		try {

			// this.rightPlayerSocket = new
			// Socket(client.getIPAddress(),client.getPort());

			BufferedReader in = new BufferedReader(new InputStreamReader(
					this.rightPlayerSocket.getInputStream()));
			PrintWriter out = new PrintWriter(
					this.rightPlayerSocket.getOutputStream());
			// BufferedReader reader = new BufferedReader(new
			// InputStreamReader(System.in));
			System.out.println("I'm sending the msg " + msg + "to the right");
			out.println(msg);
			out.flush();
			if (client.getFlag() != 1) { // I don't need to receive msg from the
											// right when I send ok
				inMsg = in.readLine();

				System.out.println("I received " + inMsg + " from the right");
			}
			// this.rightPlayerSocket.close();

		} catch (IOException ex) {
			ex.printStackTrace();

		}
	}

	public void getstatus() {
		StatusRequest Req = new StatusRequest("status");
		List<String> nicks;
		List<Client> availablePlayers = new ArrayList<Client>();
		Gson gson = new Gson();
		String json = gson.toJson(Req);
		String returnJson = tableClient.connect(json);

		StatusResponse response = gson.fromJson(returnJson,
				StatusResponse.class);
		nicks = response.getIn();
		if (nicks.size() == 1) {
			System.out
					.println("====Game Over==== you are the only one left in the play");
			System.out.println("The card is " + this.cards.get(0).getType());
			while (true) {

			}

		} else {
			for (int j = 0; j < nicks.size(); j++) {
				for (int i = 0; i < this.players.size(); i++) {
					if (nicks.get(j).equals(this.players.get(i).getNick()))
						availablePlayers.add(this.players.get(i));
				}

			}
			// this.players=availablePlayers;
			this.players.clear();
			this.players.addAll(availablePlayers);
			setLeftPlayer();
			try {
				this.leftPlayerSocket = new Socket(
						this.leftPlayer.getIPAddress(),
						this.leftPlayer.getPort());
			} catch (Exception ex) {
				ex.printStackTrace();
			}
			System.out.println("My new left player is "
					+ this.leftPlayer.getNick()
					+ this.leftPlayer.getIPAddress()
					+ this.leftPlayer.getPort());
			setRightPlayer();
			System.out.println("My new right player is "
					+ this.rightPlayer.getNick()
					+ this.rightPlayer.getIPAddress());
		}

	}

	public void sendToRightPlayer(String str) {
		try {

			OKResponse response = new OKResponse(str);
			Gson gson = new Gson();
			String json = gson.toJson(response);
			this.rightPlayer.setFlag(1);
			response(this.rightPlayer, json);

		} catch (Exception ex) {
			ex.printStackTrace();
		}

	}

	public String recievedPickCard(int cardchoosen) {

		int cardindex = cardchoosen;
		Card picked;
		Gson gson = new Gson(); // to get card number
		// pickedCardRequest req = gson.fromJson(pick, pickedCardRequest.class);

		picked = this.cards.get(cardindex);
		picked = this.cards.remove(cardindex);
		System.out.print("picked is " + picked.getType() + ", value: "
				+ picked.getValue());
		// if card number greater than cards index return error
		PickedtoSendCardRequest mypicked = new PickedtoSendCardRequest("ok",
				picked);
		String json = gson.toJson(mypicked);
		System.out.println("json is " + json);
		return json;
	}

	public boolean sendPickCardToRightPlayer(int numberofcards) {

        try {
          System.out.print("number of cards I recieved..." + numberofcards );
            int max=numberofcards-1;
            int chosen =  (int)(Math.random()*max);
            
            
            PickCardRequest Req = new PickCardRequest(chosen);
            Gson gson = new Gson();
            String json = gson.toJson(Req);


			String inMsg = null;
			try {

				BufferedReader in = new BufferedReader(new InputStreamReader(
						this.rightPlayerSocket.getInputStream()));
				PrintWriter out = new PrintWriter(
						this.rightPlayerSocket.getOutputStream());

				System.out.println("I'm sending " + json + "to the right");
				out.println(json);
				out.flush();

				inMsg = in.readLine();

				System.out.println("I received " + inMsg + " from the right");

				// this.rightPlayerSocket.close();

			} catch (IOException ex) {
				ex.printStackTrace();

			}

			PickCardResponse response = gson.fromJson(inMsg,
					PickCardResponse.class);

			if (response.getResult().equals("ok")) {
				Card card = new Card();
				card.setValue(response.getCard().get(0));
				card.setType(response.getCard().get(1));
				card.setLastCard(false); // Shall I set this attribue?

				Card pairCard = checkPair(card);

                if (pairCard == null) {
                    addCard(card);
                } else {
                    discardPairCards(card, pairCard);
                    if ((haveNoCard() == true)) {
                        
                        // send "out of cards"
                        notifyNoCards();
                        sendOfferHandToLeftPlayer();
                    } else {
                    }
                }

				return true;

			} else {
				return false;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return false;

	}

	public String waitForRightPlayer() {
		try {

			/*
			 * System.out.println("Server is waiting host = " +
			 * InetAddress.getLocalHost().getCanonicalHostName() + " port= " +
			 * myServerSocket.getLocalPort());
			 */
			this.rightPlayerSocket = this.serverSocket.accept();

			System.out.println("I got a connection from the right");

			BufferedReader myInput = new BufferedReader(new InputStreamReader(
					this.rightPlayerSocket.getInputStream()));
			PrintStream myOutput = new PrintStream(
					this.rightPlayerSocket.getOutputStream());

			String buf = myInput.readLine();

			if (buf != null) {
				System.out.println("right listener received: [" + buf + "]");

				// String type = parse(buf);
			}

			return buf;
		} catch (IOException ex) {
			ex.printStackTrace();

		}
		return null;
	}

	public boolean sendOfferHandToLeftPlayer() {

		try {
			OfferHandRequest Req = new OfferHandRequest("offer",
					this.cards.size());
			Gson gson = new Gson();
			String json = gson.toJson(Req);

			this.leftPlayer.setFlag(2); // I need to receive pick card after
										// sending ok
			String returnJson = send(this.leftPlayer, json); // return pick card
																// json

			PickCardRequest request = gson.fromJson(returnJson,
					PickCardRequest.class);

			if (request.getCmd().equals("pick")) {
				String pickedcard = recievedPickCard(request.getCardNum());
				String pickedson = send(this.leftPlayer, pickedcard);
				System.out.print("choosen card as a jason " + pickedcard
						+ " I recieved from my right " + pickedson);
				if (this.cards.size() == 0) {
					notifyNoCards();
				}

				return true;

			} else if(request.getCmd().equals("ok")){
				
				return true;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return false;
	}

	private String send(Client client, String msg) {
		String jsonmsg = msg;
		String inMsg = null;
		try {
			if (this.leftPlayerSocket == null) {
				this.leftPlayerSocket = new Socket(client.getIPAddress(),
						client.getPort());
			}
			System.out.println("The remost port is "
					+ this.leftPlayerSocket.getPort());
			BufferedReader in = new BufferedReader(new InputStreamReader(
					this.leftPlayerSocket.getInputStream()));
			PrintWriter out = new PrintWriter(
					this.leftPlayerSocket.getOutputStream());

			System.out.println("I'm sending " + msg + " to the left");
			out.println(msg);
			out.flush();

			if ((client.getFlag() == 2) || (client.getFlag() == 5)) { // I need
																		// to
																		// receive
																		// pick
																		// card
																		// after
																		// sending
																		// ok

				while (true) {
					inMsg = in.readLine();
					System.out.println("then I received " + inMsg);
					if ((client.getFlag() == 3) || (client.getFlag() == 5)) {
						// this.leftPlayerSocket.close();
						return inMsg;
					}
					// 1.ok 2. pick card
					Gson gson = new Gson();
					OutOfCardsResponse response = gson.fromJson(inMsg,
							OutOfCardsResponse.class);

					if (response.getResult().equals("ok")) {
						if (this.cards.size() == 0) {
							return inMsg;
						} else {
							client.setFlag(3);
							continue;
						}

					} else if (response.getResult().equals("out")) {

						getstatus();
						this.leftPlayer.setFlag(2);
						System.out.print("if out ");
						return (send(this.leftPlayer, jsonmsg));
					} else{
						return "failed";
					}
				}
			} else {
				if (client.getFlag() == 3) {
					this.leftPlayerSocket.close();
					this.leftPlayerSocket = null;
					return "ok";
				}
			}
		} catch (IOException ex) {
			ex.printStackTrace();
			return null;
		}

		return inMsg;
	}

	public boolean respondToRightPlayer(String str) {
		try {
			YourTurnResponse yourTurnResponse = new YourTurnResponse(str);
			Gson gson = new Gson();
			String json = gson.toJson(yourTurnResponse);
			response(this.rightPlayer, json);

			return true;
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return false;
	}

	public boolean sendYourTurnToLeftPlayer() {
		try {
			OutOfCardsRequest yourTurnReq = new OutOfCardsRequest("your_turn");
			Gson gson = new Gson();
			String json = gson.toJson(yourTurnReq);
			this.leftPlayer.setFlag(5);
			String returnJson = send(this.leftPlayer, json);

			OutOfCardsResponse response = gson.fromJson(returnJson,
					OutOfCardsResponse.class);
			if (response.getResult().equals("ok")) {
				this.leftPlayerSocket.close();
				this.leftPlayerSocket = null;
				return true;

			} else {
				return false;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return false;
	}

	public boolean discardPairCards(Card card, Card pairCard) {
		// 1.remove
		return true;
	}

	public boolean haveNoCard() {
		if (this.cards.size() == 0) {
			return true;
		} else {
			return false;
		}
	}

	public boolean isFirst() {

		for (int i = 0; i < this.players.size(); i++) {
			if (this.players.get(i).getNick().equals(this.nickName)) {
				if (i == 0) {
					return true;
				} else {
					return false;
				}
			}
		}
		return false;
	}

	public Card testdrawCard() {
		for (int i = 0; i < this.players.size(); i++) {
			if (this.players.get(i).getNick().equals(this.nickName)) {
				/*
				 * if (i == 0){ //send a draw a card json if
				 * (!sendDrawCard().equals(null)){ //add the card to the card
				 * list
				 * 
				 * } }else { //wait to receive "your turn" }
				 */
			}

		}
		return null;
	}

	public boolean isSameColor(String cardType1, String cardType2) {
		String card1 = cardType1;
		String card2 = cardType2;

		if (card1.equals("spades") && card2.equals("clubs")) {

			return true;
		} else if (card2.equals("spades") && card1.equals("clubs")) {

			return true;
		} else if (card1.equals("diamonds") && card2.equals("hearts")) {

			return true;
		} else if (card2.equals("diamonds") && card1.equals("hearts")) {

			return true;
		} else {
			return false;
		}

	}

	public Card checkPair(Card card) {

		for (int i = 0; i < this.cards.size(); i++) {
			System.out.println("cards compaired are ["
					+ this.cards.get(i).getValue() + " ,"
					+ this.cards.get(i).getType() + "],  " + card.getValue()
					+ ", " + card.getType());
			if (this.cards.get(i).getValue().equals(card.getValue())) {

				boolean colorPair = isSameColor(this.cards.get(i).getType(),
						card.getType());

				if (colorPair == true) {
					System.out.println("pair matched ");
					Card removedCard = cards.remove(i);
					sendDiscardAPairOfCards(removedCard, card);
					return card;
				}
			}
		}
		return null;
	}

	public void addCard(Card card) {
		this.cards.add(card);

	}

	private boolean isInteger(String input) {
		try {
			Integer.parseInt(input);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	private void sendDiscardAPairOfCards(Card removedCard, Card card) {
		try {
			boolean aType = isInteger(removedCard.getValue()); // true: number,
																// false: string
			boolean bType = isInteger(card.getValue());

			String json;
			Gson gson = new Gson();

			if ((aType == true) && (bType == true)) {
				DiscardCardNumber numberReq = new DiscardCardNumber("discard",
						card.isLastCard());
				numberReq.fillinCards(removedCard, card);

				json = gson.toJson(numberReq);
			} else if ((aType == false) && (bType == false)) {
				DiscardCardString stringReq = new DiscardCardString("discard",
						card.isLastCard());
				stringReq.fillinCards(removedCard, card);

				json = gson.toJson(stringReq);
			} else {
				DiscardCardsRequest mixReq = new DiscardCardsRequest("discard",
						card.isLastCard());
				mixReq.fillinCards(removedCard, card);

				json = gson.toJson(mixReq);
			}

			System.out.println(json);
			String returnJson = tableClient.connect(json);
			DiscardCardsResponse response = gson.fromJson(returnJson,
					DiscardCardsResponse.class);
			if (response.getResult().equals("ok")) {
				System.out.print("Cards discarded successfully");
			} else {
				System.out
						.print("Unable to discarded cards...game exiting...please try the game again");
				System.exit(1);
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	private void insertAll(Response res) {

		try {
			this.players.clear();
			for (Map.Entry<List<String>, String> e : res.players.entrySet()) {
				System.out.println(e.getValue());
				Client client = new Client();
				client.setNick(e.getValue());
				// List<String> address = new ArrayList<String>();
				for (String s : e.getKey()) {
					System.out.println(s);
					if (e.getKey().indexOf(s) == 0) {
						String aa = s.substring(7);
						client.setIPAddress(aa);

					} else {

						client.setPort(Integer.parseInt(s));
					}
				}

				this.players.add(client);

			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	/*
	 * private void printPlayers(){ for(Map.Entry<String,List<String>> e :
	 * this.players.entrySet()){ System.out.print("nick: " + e.getKey());
	 * 
	 * for(String s : e.getValue()){
	 * 
	 * if(e.getValue().indexOf(s) == 0) { System.out.print("IP: " + s); }else {
	 * System.out.print("port: " + s); } } System.out.println();
	 * 
	 * 
	 * } }
	 */
	/*
	 * private void setLeftPlayer(Response res){
	 * 
	 * Iterator<Entry<List<String>, String>> keyValuePairs1 =
	 * res.players.entrySet().iterator();
	 * 
	 * for (int i = 0; i< res.players.size(); i++) {
	 * 
	 * Map.Entry<List<String>, String> entry = (Map.Entry<List<String>,
	 * String>)keyValuePairs1.next(); String nick = entry.getValue();
	 * if(nick.equals(nickName)){
	 * 
	 * } Object value = entry.getValue(); ... } for(Map.Entry<List<String>,
	 * String> e : res.players.entrySet()){ if(e.){
	 * 
	 * }
	 * 
	 * for(String s : e.getKey()){ System.out.println(s); } } }
	 */
	public boolean notifyNoCards() {

		try {
			OutOfCardsRequest notifyNoCards = new OutOfCardsRequest(
					"out_of_cards");
			Gson gson = new Gson();
			String json = gson.toJson(notifyNoCards);
			String returnJson = tableClient.connect(json);

			OutOfCardsResponse response = gson.fromJson(returnJson,
					OutOfCardsResponse.class);
			if (response.getResult().equals("ok")) {
				System.out.println("NO CARDS");
				return true;

			} else {
				return false;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return false;

	}

	private void setLeftPlayer() {
		for (int i = 0; i < players.size(); i++) {
			Client c = players.get(i);
			if (c.getNick().equals(this.nickName)) {
				if (i == this.players.size() - 1) {
					this.leftPlayer = this.players.get(0);
				} else {
					this.leftPlayer = this.players.get(i + 1);
				}
			}
		}

	}

	private void setRightPlayer() {

		for (int i = 0; i < players.size(); i++) {
			Client c = players.get(i);
			if (c.getNick().equals(nickName)) {
				if (i == 0) {
					this.rightPlayer = players.get(players.size() - 1);
				} else {
					this.rightPlayer = players.get(i - 1);
				}
			}
		}

	}

	public void joinGame() {

		try {
			JoinGameRequest joinGameReq = new JoinGameRequest("join", nickName,
					localPort);
			Gson gson = new Gson();
			String json = gson.toJson(joinGameReq);
			String returnJson = tableClient.connect(json);
			Response response = gson.fromJson(returnJson, Response.class);
			if (response.getResult().equals("ok")) {
				response.listPlayers();
				insertAll(response);
				// printPlayers();
				System.out.println(players.size());
				setLeftPlayer();
				System.out.println("My left player is "
						+ this.leftPlayer.getNick()
						+ this.leftPlayer.getIPAddress());
				setRightPlayer();
				System.out.println("My right player is "
						+ this.rightPlayer.getNick()
						+ this.rightPlayer.getIPAddress());
			} else {

			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}

	}

	public Card drawCard() {
		try {
			DrawCardRequest drawCardReq = new DrawCardRequest("draw");
			Gson gson = new Gson();
			String json = gson.toJson(drawCardReq);
			String returnJson = tableClient.connect(json);
			Card card = new Card();
			DrawCardResponse response = gson.fromJson(returnJson,
					DrawCardResponse.class);
			if (response.getResult().equals("ok")) {

				card.setValue(response.getCard().get(0));
				card.setType(response.getCard().get(1));
				card.setLastCard(false);

				return card;
			} else if (response.getResult().equals("last_card")) {
				card.setValue(response.getCard().get(0));
				card.setType(response.getCard().get(1));
				card.setLastCard(true);

				return card;

			} else {
				return null;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return null;
	}

}
